package com.ys.load.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.http.impl.client.CloseableHttpClient;

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.java.core.cipher.Verifier;

/**
 * WX支付签名证书工具类
 * @author 何帆
 * @createTime 2024/7/15 上午9:46
 * @lastEdit 何帆
 * @lastEditTime
 */
public class WXPaySignatureCertificateUtil {
 
    private static final ConcurrentHashMap<String, Verifier> verifierMaps = new ConcurrentHashMap<>();
 
   /**
     * 证书验证
     * 自动更新的签名验证器
     */
    public static CloseableHttpClient checkSign() throws IOException {
        //验签
        CloseableHttpClient httpClient = null;
        PrivateKey merchantPrivateKey = WXPaySignatureCertificateUtil.getPrivateKey();
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(WxV3PayConfig.Mch_ID, WxV3PayConfig.mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator((com.wechat.pay.contrib.apache.httpclient.auth.Verifier) WXPaySignatureCertificateUtil.getVerifiers(WxV3PayConfig.mchSerialNo)))
                .build();
        return httpClient;
    }
        
 
 
    /**
     * 功能描述:获取平台证书，自动更新
     * 注意：这个方法内置了平台证书的获取和返回值解密
     */
    public static Verifier getVerifiers(String mchSerialNo) {
        Verifier verifier = null;
        if (verifierMaps.isEmpty() || !verifierMaps.containsKey(mchSerialNo)) {
            verifierMaps.clear();
            try {
                PrivateKey privateKey = getPrivateKey();
                //刷新
                PrivateKeySigner signer = new PrivateKeySigner(mchSerialNo, privateKey);
                WechatPay2Credentials credentials = new WechatPay2Credentials(WxV3PayConfig.Mch_ID, signer);
                verifier = (Verifier) new AutoUpdateCertificatesVerifier(credentials, WxV3PayConfig.apiV3Key.getBytes(StandardCharsets.UTF_8));
                verifierMaps.put(((AutoUpdateCertificatesVerifier) verifier).getValidCertificate().getSerialNumber()+"", verifier);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            verifier = verifierMaps.get(mchSerialNo);
        }
        return verifier;
    }
 
 
    /**
     * app生成带签名支付信息
     *
     * @param timestamp 时间戳
     * @param nonceStr  随机数
     * @param prepayId  预付单
     * @return 支付信息
     * @throws Exception
     */
    public static String appPaySign(String timestamp, String nonceStr, String prepayId) throws Exception {
        //上传私钥
        PrivateKey privateKey = getPrivateKey();
        String signatureStr = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(sign.sign());
    }
 
    public static void main(String[] args) throws Exception{
    	String sss = String.valueOf(System.currentTimeMillis());
    	System.out.println(sss);
		String ss = appPaySign(sss,"qwerty","c005211e8c8242aca7aa0212fb660880");
		System.out.println(ss);
	}
    
    /**
     * 获取私钥。
     * 证书路径 本地使用如： D:\\微信平台证书工具\\7.9\\apiclient_key.pem
     * 证书路径 线上使用如： /usr/apiclient_key.pem
     * String filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey() throws IOException {
        String content = new String(Files.readAllBytes(Paths.get(WxV3PayConfig.path)), StandardCharsets.UTF_8);
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }
}
